﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

using SimpleIR;
using PInfoModel;

namespace PIPostAnalysis.ValueTypes
{
	public static class MutationAndNullityChecksExtractor
	{
		public static MutationAndNullityCheckInfo ExtractMutationAndNullityForProg(CompleteAnalysisInfoForProgram pip)
		{
			MutationAndNullityCheckInfo mni = new MutationAndNullityCheckInfo(pip.Program);

			foreach(CompleteAnalysisInfoMethod cmi in pip.MethodInfo.Values)
			{
				bool isctor = cmi.InvokeID.Sig.IsConstructor;
				IRBodyDef mdef = pip.Program.MethodBodyTable.GetBodyForInvokeExactSigMatch(cmi.InvokeID);
				IRType rettype = mdef.ReturnType == pip.Program.TypeTable.VoidType ? null : mdef.ReturnType;

				foreach(CompleteAnalysisInfoMethodContext cci in cmi.AllCallContexts)
					mni.VisitSingleMethodContext(isctor, rettype, mdef.Body.BasicBlockList, cci, pip);
			}

			return mni;
		}
	}

	/// <summary>
	/// This class contains information on the assignment and comparison of null pointers to fields/vars 
	/// of types that we are interested in converting to value types.
	/// </summary>
	public sealed class MutationAndNullityCheckInfo
	{
		/// <summary>
		/// Lines where a pointer to the given class may be compared with null.
		/// </summary>
		public Dictionary<IRClassType, HashSet<ProgLineIdentifier>> MayCompareWithNullLines;

		/// <summary>
		/// Lines where a pointer to the given class may be compared with a non-null value.
		/// </summary>
		public Dictionary<IRClassType, HashSet<ProgLineIdentifier>> MayCompareWithNonNullLines;

		/// <summary>
		/// Lines where a pointer to the given class may be assigned a null value.
		/// </summary>
		public Dictionary<IRClassType, HashSet<ProgLineIdentifier>> ExplicitNullAssignLines;

		/// <summary>
		/// Lines where a class may be modified.
		/// </summary>
		public Dictionary<IRClassType, HashSet<ProgLineIdentifier>> ClassMutatedLines;

		/// <summary>
		/// Lines where a class may be modified and in a way that is not known to be uniquely visible.
		/// </summary>
		public Dictionary<IRClassType, HashSet<ProgLineIdentifier>> MultiVisibleMutatedLines;

		internal static bool IsTypeInteresting(IRType tt)
		{
			if(!(tt is IRClassType) || tt.TypeDescription.IsBuiltinType)
				return false;

			TypeQualifiers ignoretq = TypeQualifiers.StaticTag | TypeQualifiers.InterfaceTag | TypeQualifiers.AbstractTag;
			return (tt.TypeDescription.TypeQualifierInfo & ignoretq) == TypeQualifiers.Clear;
		}

		public MutationAndNullityCheckInfo(IRProgram p)
		{
			this.MayCompareWithNullLines = new Dictionary<IRClassType, HashSet<ProgLineIdentifier>>();
			this.MayCompareWithNonNullLines = new Dictionary<IRClassType, HashSet<ProgLineIdentifier>>();
			this.ExplicitNullAssignLines = new Dictionary<IRClassType, HashSet<ProgLineIdentifier>>();

			this.ClassMutatedLines = new Dictionary<IRClassType, HashSet<ProgLineIdentifier>>();
			this.MultiVisibleMutatedLines = new Dictionary<IRClassType, HashSet<ProgLineIdentifier>>();

			List<IRType> allt = p.TypeTable.AllDefinedTypes;
			foreach(IRType tt in allt)
			{
				if(IsTypeInteresting(tt))
				{
					this.MayCompareWithNullLines.Add((IRClassType)tt, new HashSet<ProgLineIdentifier>());
					this.MayCompareWithNonNullLines.Add((IRClassType)tt, new HashSet<ProgLineIdentifier>());
					this.ExplicitNullAssignLines.Add((IRClassType)tt, new HashSet<ProgLineIdentifier>());

					this.ClassMutatedLines.Add((IRClassType)tt, new HashSet<ProgLineIdentifier>());
					this.MultiVisibleMutatedLines.Add((IRClassType)tt, new HashSet<ProgLineIdentifier>());
				}
			}
		}

		public string EmitString()
		{
			StringBuilder sb = new StringBuilder("++++++++\nNullityInfo:\n");

			sb.Append("MayNullCompare = {\n");
			foreach(KeyValuePair<IRClassType, HashSet<ProgLineIdentifier>> kkp in this.MayCompareWithNullLines)
			{
				sb.Append("\t" + kkp.Key.ToString() + " -> { ");
				List<ProgLineIdentifier> sl = new List<ProgLineIdentifier>(kkp.Value);
				sl.Sort();

				foreach(ProgLineIdentifier pli in sl)
					sb.Append(pli.SourceLine.ToString() + " ");
				sb.Append("}\n");
			}
			sb.Append("}\n\n");

			sb.Append("MayNonNullCompare = {\n");
			foreach(KeyValuePair<IRClassType, HashSet<ProgLineIdentifier>> kkp in this.MayCompareWithNonNullLines)
			{
				sb.Append("\t" + kkp.Key.ToString() + " -> { ");
				List<ProgLineIdentifier> sl = new List<ProgLineIdentifier>(kkp.Value);
				sl.Sort();

				foreach(ProgLineIdentifier pli in sl)
					sb.Append(pli.SourceLine.ToString() + " ");
				sb.Append("}\n");
			}
			sb.Append("}\n\n");

			sb.Append("ExplicitNullAssign = {\n");
			foreach(KeyValuePair<IRClassType, HashSet<ProgLineIdentifier>> kkp in this.ExplicitNullAssignLines)
			{
				sb.Append("\t" + kkp.Key.ToString() + " -> { ");
				List<ProgLineIdentifier> sl = new List<ProgLineIdentifier>(kkp.Value);
				sl.Sort();

				foreach(ProgLineIdentifier pli in sl)
					sb.Append(pli.SourceLine.ToString() + " ");
				sb.Append("}\n");
			}
			sb.Append("}\n\n");

			sb.Append("++++++++\nMutationInfo:\n");

			sb.Append("ClassMutatedLines = {\n");
			foreach(KeyValuePair<IRClassType, HashSet<ProgLineIdentifier>> kkp in this.ClassMutatedLines)
			{
				sb.Append("\t" + kkp.Key.ToString() + " -> { ");
				List<ProgLineIdentifier> sl = new List<ProgLineIdentifier>(kkp.Value);
				sl.Sort();

				foreach(ProgLineIdentifier pli in sl)
					sb.Append(pli.SourceLine.ToString() + " ");
				sb.Append("}\n");
			}
			sb.Append("}\n\n");

			sb.Append("MultiVisibleMutatedLines = {\n");
			foreach(KeyValuePair<IRClassType, HashSet<ProgLineIdentifier>> kkp in this.MultiVisibleMutatedLines)
			{
				sb.Append("\t" + kkp.Key.ToString() + " -> { ");
				List<ProgLineIdentifier> sl = new List<ProgLineIdentifier>(kkp.Value);
				sl.Sort();

				foreach(ProgLineIdentifier pli in sl)
					sb.Append(pli.SourceLine.ToString() + " ");
				sb.Append("}\n");
			}
			sb.Append("}\n\n");

			return sb.ToString();
		}

		internal void VisitSingleMethodContext(bool isctor, IRType rettype, List<IRBasicBlock> bbset, CompleteAnalysisInfoMethodContext ccm, CompleteAnalysisInfoForProgram cip)
		{
			Dictionary<int, ProgramPointInfo> ppinfo = ccm.ProgramPointToPointInfoMap();

			foreach(IRBasicBlock bb in bbset)
			{
				if(!ccm.BlockIDToStateMap.ContainsKey(bb.BlockID))
					continue;

				foreach(IRByteCode bc in bb.Operations)
				{
					ProgramPointInfo ppi = ppinfo[bc.UseModLoc];
					if(ppi == null || ppi.PreOperationModel == null)
						continue;

					PIModel pm = ppi.PreOperationModel;
					switch(bc.OperationCode)
					{
						case OpCode.Op.AllocCons:
							if(((IRAllocationOp)bc).AllocType is IRContainerType && ((IRContainerType)((IRAllocationOp)bc).AllocType).IsArrayContainer)
							{ ;}
							else
								this.CheckMethodArgsForNullPtrs(bc, ((IRAllocationOp)bc).ConsIdentity.Sig);
							break;
						case OpCode.Op.ArrayStore:
							this.ProcessArrayStore((IRStoreFromEvalStackIndirect)bc);
							break;
						case OpCode.Op.Call:
							this.CheckMethodArgsForNullPtrs(bc, ((IRCallOp)bc).InvokeSig);
							break;
						case OpCode.Op.CallVirt:
							this.CheckMethodArgsForNullPtrs(bc, ((IRCallOp)bc).InvokeSig);
							break;
						case OpCode.Op.Cast:
							this.ProcessCast((IREvalStackTypeOp)bc);
							break;
						case OpCode.Op.DerefableEQ:
							this.ProcessEQCheck((IREvalStackOp)bc);
							break;
						case OpCode.Op.IndirectInitialize:
							this.ProcessIndirectInitialize((IRStoreFromEvalStackIndirect)bc, pm);
							break;
						case OpCode.Op.IndirectWrite:
							this.ProcessIndirectWrite(isctor, (IRStoreFromEvalStackIndirect)bc, pm);
							break;
						case OpCode.Op.NonNull:
							this.ProcessNonNullCheck((IREvalStackOp)bc);
							break;
						case OpCode.Op.Return:
							this.ProcessReturn(isctor, rettype, bc);
							break;
						case OpCode.Op.StoreMemberField:
							this.ProcessStoreToMemberField(isctor, (IRStoreFromEvalStackIndirect)bc, pm, cip, ccm);
							break;
						case OpCode.Op.StoreToGlobal:
							this.ProcessStoreToGlobal((IRStoreFromEvalStackBasic)bc, pm);
							break;
						case OpCode.Op.StoreToLocal:
							this.ProcessStoreToLocal((IRStoreFromEvalStackBasic)bc, pm);
							break;
						default:
							break;
					}
				}
			}
		}

		private void CheckMethodArgsForNullPtrs(IRByteCode bc, IRInvokeSig csig)
		{
			for(int i = 0; i < csig.InvokeSig.Count; ++i)
			{
				if(csig.InvokeSig[i] is IRPtrType && IsTypeInteresting(((IRPtrType)csig.InvokeSig[i]).PtrTargetType))
				{
					int spos = csig.InvokeSig.Count - (i + 1);
					SymbolicEvalStackTerm evest = bc.SymEvalStack.GetTermAtPos(spos);
					if(((IRPtrType)evest.SType).IsNullPointer)
						this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)csig.InvokeSig[i]).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
				}
			}
		}

		private void ProcessArrayStore(IRStoreFromEvalStackIndirect bc)
		{
			if(bc.ArrayStoreType.ContainerContentsType is IRPtrType && IsTypeInteresting(((IRPtrType)bc.ArrayStoreType.ContainerContentsType).PtrTargetType))
			{
				SymbolicEvalStackTerm evest = bc.SymEvalStack.GetTermAtPos(0);
				if(((IRPtrType)evest.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)bc.ArrayStoreType.ContainerContentsType).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessCast(IREvalStackTypeOp bc)
		{
			if(bc.TypeArg is IRPtrType && IsTypeInteresting(((IRPtrType)bc.TypeArg).PtrTargetType))
			{
				SymbolicEvalStackTerm evest = bc.SymEvalStack.GetTermAtPos(0);
				if(((IRPtrType)evest.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)bc.TypeArg).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessEQCheck(IREvalStackOp bc)
		{
			IRType tt0 = bc.SymEvalStack.GetTermAtPos(0).SType;
			IRType tt1 = bc.SymEvalStack.GetTermAtPos(1).SType;

			if(tt0 is IRPtrType && !((IRPtrType)tt0).IsNullPointer && IsTypeInteresting(((IRPtrType)tt0).PtrTargetType))
			{
				SymbolicEvalStackTerm cmpw = bc.SymEvalStack.GetTermAtPos(1);
				if(((IRPtrType)cmpw.SType).IsNullPointer)
					this.MayCompareWithNullLines[(IRClassType)((IRPtrType)tt0).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
				else
					this.MayCompareWithNonNullLines[(IRClassType)((IRPtrType)tt0).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}

			if(tt1 is IRPtrType && !((IRPtrType)tt1).IsNullPointer && IsTypeInteresting(((IRPtrType)tt1).PtrTargetType))
			{
				SymbolicEvalStackTerm cmpw = bc.SymEvalStack.GetTermAtPos(0);
				if(((IRPtrType)cmpw.SType).IsNullPointer)
					this.MayCompareWithNullLines[(IRClassType)((IRPtrType)tt1).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
				else
					this.MayCompareWithNonNullLines[(IRClassType)((IRPtrType)tt1).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessIndirectInitialize(IRStoreFromEvalStackIndirect bc, PIModel premodel)
		{
			//check if we are storing null into a ptr
			IRType stltype = bc.ThroughRefType.ReferenceTargetType;
			if(stltype is IRPtrType && IsTypeInteresting(((IRPtrType)stltype).PtrTargetType))
				this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)stltype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));

			PISNode mevstck = premodel.GetEvalStackNodeAtPos(0);
			foreach(PIMEdge trgte in mevstck.Targets)
			{
				PIMNode trgtn = premodel.Nodes[trgte.TargetAddress];
				if(!IsTypeInteresting(trgtn.LocationType))
					continue;

				this.ClassMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
				this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessIndirectWrite(bool isctor, IRStoreFromEvalStackIndirect bc, PIModel premodel)
		{
			//check if we are storing null into a ptr
			IRType stltype = bc.ThroughRefType.ReferenceTargetType;
			if(stltype is IRPtrType && IsTypeInteresting(((IRPtrType)stltype).PtrTargetType))
			{
				PISNode evstck = premodel.GetEvalStackNodeAtPos(0);
				if(((IRPtrType)evstck.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)stltype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}

			//now look at which class is being mutated
			SymbolicEvalStackTerm trgtterm = bc.SymEvalStack.GetTermAtPos(1);
			if(isctor && trgtterm.SymTerm == SymbolicEvalStackTerm.TermTag.Var && trgtterm.TermRoot.NameString.Equals("this"))
				return;

			PISNode mevstck = premodel.GetEvalStackNodeAtPos(1);
			foreach(PIMEdge trgte in mevstck.Targets)
			{
				PIMNode trgtn = premodel.Nodes[trgte.TargetAddress];
				if(!IsTypeInteresting(trgtn.LocationType))
					continue;

				this.ClassMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
				this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessReturn(bool isctor, IRType rettype, IRByteCode bc)
		{
			if(!isctor && rettype != null && rettype is IRPtrType && IsTypeInteresting(((IRPtrType)rettype).PtrTargetType) && ((IRPtrType)bc.SymEvalStack.GetTermAtPos(0).SType).IsNullPointer)
				this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)rettype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
		}

		private void ProcessNonNullCheck(IREvalStackOp bc)
		{
			IRType tt = bc.SymEvalStack.GetTermAtPos(0).SType;
			if(tt is IRPtrType && IsTypeInteresting(((IRPtrType)tt).PtrTargetType))
				this.MayCompareWithNullLines[(IRClassType)((IRPtrType)tt).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
		}

		private void ProcessStoreToMemberField(bool isctor, IRStoreFromEvalStackIndirect bc, PIModel premodel, CompleteAnalysisInfoForProgram cip, CompleteAnalysisInfoMethodContext ccm)
		{
			//check if we are storing null into a ptr
			IRType stltype = bc.WriteField.FieldType;
			if(stltype is IRPtrType && IsTypeInteresting(((IRPtrType)stltype).PtrTargetType))
			{
				PISNode evstck = premodel.GetEvalStackNodeAtPos(0);
				if(((IRPtrType)evstck.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)stltype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}

			//now look at which class is being mutated
			SymbolicEvalStackTerm trgtterm = bc.SymEvalStack.GetTermAtPos(1);
			if(isctor && trgtterm.SymTerm == SymbolicEvalStackTerm.TermTag.Var && trgtterm.TermRoot.NameString.Equals("this"))
				return;

			PISNode mevstck = premodel.GetEvalStackNodeAtPos(1);
			foreach(PIMEdge trgte in mevstck.Targets)
			{
				PIMNode trgtn = premodel.Nodes[trgte.TargetAddress];
				if(!IsTypeInteresting(trgtn.LocationType))
					continue;

				this.ClassMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));

				if(trgtn.ExtRefInto.Length != 0)
				{
					bool isloadwkillofthis = trgtn.InEdges.Count == 1 && trgtn.InEdges[0].IsEvalStackSource && bc.SymEvalStack.GetTermAtPos(1).SymTerm == SymbolicEvalStackTerm.TermTag.Var && bc.SymEvalStack.GetTermAtPos(1).TermRoot.NameString.Equals("this");
					bool isloadofthis = trgtn.InEdges.Count == 2 && trgtn.InEdges.Exists((PIMEdge ee) => !ee.IsEvalStackSource) && bc.SymEvalStack.GetTermAtPos(1).SymTerm == SymbolicEvalStackTerm.TermTag.Var && bc.SymEvalStack.GetTermAtPos(1).TermRoot.NameString.Equals("this");

					if(!isloadwkillofthis && !isloadofthis)
						this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
					else if(isloadwkillofthis)
					{
						bool allcallsok = this.CallerCheck(cip, ccm);
						if(!allcallsok)
							this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
					}
					else
					{
						PIMEdge oe = trgtn.InEdges.First((PIMEdge ee) => !ee.IsEvalStackSource);
						PIMNode osn = premodel.Nodes[oe.SourceAddress];
						if(osn.HomeLocFor == null || !osn.HomeLocFor.RootNameString().Equals("this"))
							this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
						else
						{
							bool allcallsok = this.CallerCheck(cip, ccm);
							if(!allcallsok)
								this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
						}

					}
					
				}
				else
				{
					if(trgtn.InEdges.Count == 1)
					{ ;}
					else if(trgtn.InEdges.Count > 2 || trgtn.InEdges.Count((PIMEdge ee) => ee.IsEvalStackSource) != 1)
						this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
					else
					{
						PIMEdge oe = trgtn.InEdges.First((PIMEdge ee) => !ee.IsEvalStackSource);
						if(!oe.IsInjective)
							this.MultiVisibleMutatedLines[(IRClassType)trgtn.LocationType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
					}
				}
			}
		}

		private bool CallerCheck(CompleteAnalysisInfoForProgram cip, CompleteAnalysisInfoMethodContext ccm)
		{
			IRInvokeSig csig = ccm.InvokeID.Sig;
			if(!csig.IsVirtualInvoke)
				return false;

			IRVirtualInvoke vsig = (IRVirtualInvoke)csig;
			int rcvrpos = vsig.InvokeSig.Count;

			foreach(Tuple<IRInvokeIdentity, int, int> calleri in ccm.CallersContextsAndLines)
			{
				CompleteAnalysisInfoMethod cmethod = cip.MethodInfo[calleri.Item1];
				CompleteAnalysisInfoMethodContext cctx = cmethod.AllCallContexts.Find((CompleteAnalysisInfoMethodContext ccf) => ccf.ContextID == calleri.Item2);
				Dictionary<int, ProgramPointInfo> ppinfo = cctx.ProgramPointToPointInfoMap();
				PIModel cstate = ppinfo[calleri.Item3].PreOperationModel;

				PISNode rcvrnode = cstate.GetEvalStackNodeAtPos(rcvrpos);
				foreach(PIMEdge ee in rcvrnode.Targets)
				{
					PIMNode nn = cstate.Nodes[ee.TargetAddress];
					if(nn.ExtRefInto.Length != 0)
						return false;
					else
					{
						if(nn.InEdges.Count == 1)
							return true;
						else if(nn.InEdges.Count > 2 || nn.InEdges.Count((PIMEdge tee) => tee.IsEvalStackSource) != 1)
							return false;
						else
						{
							PIMEdge oe = nn.InEdges.First((PIMEdge tee) => !tee.IsEvalStackSource);
							if(!oe.IsInjective)
								return false;
						}
					}
				}
			}

			return true;
		}

		private void ProcessStoreToGlobal(IRStoreFromEvalStackBasic bc, PIModel premodel)
		{
			IRType stltype = premodel.ResolveHomeForRoot(bc.StaticField).LocationType;

			if(stltype is IRPtrType && IsTypeInteresting(((IRPtrType)stltype).PtrTargetType))
			{
				PISNode evstck = premodel.GetEvalStackNodeAtPos(0);
				if(((IRPtrType)evstck.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)stltype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}

		private void ProcessStoreToLocal(IRStoreFromEvalStackBasic bc, PIModel premodel)
		{
			IRType stltype = premodel.ResolveHomeForRoot(bc.LocalVar).LocationType;

			if(stltype is IRPtrType && IsTypeInteresting(((IRPtrType)stltype).PtrTargetType))
			{
				PISNode evstck = premodel.GetEvalStackNodeAtPos(0);
				if(((IRPtrType)evstck.SType).IsNullPointer)
					this.ExplicitNullAssignLines[(IRClassType)((IRPtrType)stltype).PtrTargetType].Add(new ProgLineIdentifier(bc.UseModLoc, bc.SourceLocationInfo));
			}
		}
	}
}
